package com.meilai.project.controller.web.adMake.service;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.meilai.project.constant.*;
import com.meilai.project.controller.web.adMake.dto.*;
import com.meilai.project.controller.web.adMake.entity.*;
import com.meilai.project.controller.web.adMake.mapper.BillAdMakeMapper;
import com.meilai.project.controller.web.adMake.vo.*;
import com.meilai.project.controller.web.market.entity.BillMarketDesignPic;
import com.meilai.project.controller.web.market.service.BillMarketDesignPicService;
import com.meilai.project.dto.finance.supplier.SupplierMaterialCalDTO;
import com.meilai.project.dto.workflow.FlowBusinessDataSuperEntity;
import com.meilai.project.dto.workflow.WorkFlowCheckDTO;
import com.meilai.project.entity.business.customer.CustomerInfo;
import com.meilai.project.entity.finance.supplier.SupplierMaterial;
import com.meilai.project.exception.CommonException;
import com.meilai.project.service.business.customer.CustomerInfoService;
import com.meilai.project.service.finance.supplier.SupplierMaterialService;
import com.meilai.project.service.system.impl.UserServiceImpl;
import com.meilai.project.util.ThreadLocalUserUtil;
import com.meilai.project.util.WorkFlowUtil;
import com.meilai.project.vo.system.UserForWFVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author yxg
 * @Date 2022/8/3 0:47
 */
@Service
@Slf4j
public class BillAdMakeServiceImpl extends ServiceImpl<BillAdMakeMapper, BillAdMake> implements BillAdMakeService {


    @Autowired
    private BillAdMakeDeliverService billAdMakeDeliverService;
    @Autowired
    private BillAdMakeDisSupplierService billAdMakeDisSupplierService;
    @Autowired
    private BillAdMakeMarkService billAdMakeMarkService;
    @Autowired
    private BillAdMakePicService billAdMakePicService;
    @Autowired
    private BillAdMakeSupplierConfirmService billAdMakeSupplierConfirmService;
    @Autowired
    private BillAdMakeSupplierConfirmPriceService billAdMakeSupplierConfirmPriceService;

    @Autowired
    private BillMarketDesignPicService billMarketDesignPicService;
    @Autowired
    private CustomerInfoService customerInfoService;
    @Autowired
    private SupplierMaterialService supplierMaterialService;

    @Autowired
    private PlatformTransactionManager platformTransactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;

    /**
     * @description 根据市场单id，获取点位数据
     * @param marketId 市场单id
     * @author 张驰
     * @date 2022/8/16 10:40
     */
    @Override
    public BillAdMakePointFromMarketVO getPointsByMarketId(Long marketId) {
        BillAdMakePointFromMarketVO result = new BillAdMakePointFromMarketVO();

        // 设置“是否需要小样”
        BillAdMakePointFromMarketVO bm = baseMapper.getVOByMarketId(marketId);
        if(bm == null) return result;
        BeanUtils.copyProperties(bm, result);

        // todo 目前系统不存在“换画”类型的时长单，此处暂时全部返回“正常”
        result.setDict_class_out_id(AdMakeOutTypeEnum.REPLACE.getId());
        result.setDict_class_out_name(AdMakeOutTypeEnum.REPLACE.getName());

        // 设置“画面urls”
        List<BillMarketDesignPic> pics = billMarketDesignPicService.list(Wrappers.<BillMarketDesignPic>lambdaQuery()
                .select(BillMarketDesignPic::getPic_url).eq(BillMarketDesignPic::getBill_market_id, marketId));
        if(CollectionUtils.isEmpty(pics)) return result;
        result.setPicList(pics.stream()
                .filter(d -> StringUtils.isNotEmpty(d.getPic_url()))
                .map(BillMarketDesignPic::getPic_url).collect(Collectors.toList()));

        // 设置“点位数据”
        List<BillAdMakePointDTO> points = baseMapper.getPointsByMarketId(marketId);
        if(CollectionUtils.isEmpty(points)) return result;
        List<BillAdMakePointDetailFromMarketVO> pointVOs = new ArrayList<>();
        // 综合市场
        List<BillAdMakePointDTO> points_9 = points.stream().filter(d -> d.getMedia_type_id().equals(9L)).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(points_9)){
            Map<String, List<BillAdMakePointDTO>> pMap_9 =
                    points_9.stream().collect(Collectors.groupingBy(d -> d.getName()+"_"+d.getSize_width()+"_"+d.getSize_height()+"_"+d.getMedia_pic_type_id(), Collectors.toList()));
            assembleBillAdMakePointDetailFromMarketVO(pointVOs, pMap_9);
        }
        // 其他类型
        List<BillAdMakePointDTO> points_not_9 = points.stream().filter(d -> !d.getMedia_type_id().equals(9L)).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(points_not_9)){
            Map<String, List<BillAdMakePointDTO>> pMap_not_9 =
                    points_not_9.stream().collect(Collectors.groupingBy(d -> d.getMedia_type_id()+"_"+d.getSize_width()+"_"+d.getSize_height()+"_"+d.getMedia_pic_type_id(), Collectors.toList()));
            assembleBillAdMakePointDetailFromMarketVO(pointVOs, pMap_not_9);
        }
        if(CollectionUtils.isEmpty(pointVOs)) return result;
        result.setPointList(pointVOs);

        return result;
    }

    private void assembleBillAdMakePointDetailFromMarketVO(List<BillAdMakePointDetailFromMarketVO> pointVOs, Map<String, List<BillAdMakePointDTO>> pMap) {
        for(Map.Entry<String, List<BillAdMakePointDTO>> entry : pMap.entrySet()){
            if(CollectionUtils.isNotEmpty(entry.getValue())){
                BillAdMakePointDetailFromMarketVO temp = new BillAdMakePointDetailFromMarketVO();
                BeanUtils.copyProperties(entry.getValue().get(0), temp);
                temp.setMedia_type_spec(temp.getSize_width()+"*"+temp.getSize_height());
                temp.setCount(entry.getValue().size());
                pointVOs.add(temp);
            }
        }
    }

    @Override
    public List<JSONObject> listMediaTypeSpec(Long media_type_id) {
        List<JSONObject> list = new ArrayList<>();
        list = baseMapper.listMediaTypeSpec(media_type_id);
//        JSONObject jsonObject = new JSONObject();
//        jsonObject.put("size_width", null);
//        jsonObject.put("size_height", null);
//        jsonObject.put("name", "无");
//        list.add(jsonObject);
        return list;
    }

    @Override
    public List<JSONObject> listMediaPicType(Long media_type_id, String size_width, String size_height) {
        List<JSONObject> list = new ArrayList<>();
        if (media_type_id != null && StringUtils.isNotEmpty(size_width) && StringUtils.isNotEmpty(size_height))
            list = baseMapper.listMediaPicType(media_type_id, size_width, size_height);
//        JSONObject jsonObject = new JSONObject();
//        jsonObject.put("id", null);
//        jsonObject.put("name", "无");
//        list.add(jsonObject);
        return list;
    }

    @Override
    public BillAdMakeWebVO supplierConfirmLinkData(Long adMakeId) {
        BillAdMakeWebVO result = new BillAdMakeWebVO();

        BillAdMakeSearchParams params = new BillAdMakeSearchParams();
        List<Long> ids = new ArrayList<>();
        ids.add(adMakeId);
        params.setIds(ids);
        List<BillAdMakeWebVO> vos = baseMapper.selectPageList(params);
        if(CollectionUtils.isNotEmpty(vos) && vos.size() == 1){
            result = vos.get(0);

            List<BillAdMakeSupplierConfirmVO> confirmVOs = new ArrayList<>();
            if(result.getFlow_status().equals(FlowStatusEnum.PASSED.getId())){
                // 只有审批通过的制作单，才会显示待生成链接列表
                confirmVOs = billAdMakeSupplierConfirmService.confirmVOList(adMakeId);
            }
            if(CollectionUtils.isNotEmpty(confirmVOs)){
                Set<Long> supplierIds = confirmVOs.stream().map(BillAdMakeSupplierConfirmVO::getSupplier_id).collect(Collectors.toSet());
                if(CollectionUtils.isNotEmpty(supplierIds)){
                    // 画面
                    Map<Long, List<String>> supplierPicMap = new HashMap<>();
                    List<BillAdMakePicsForConfirmDTO> supplierPicList = billAdMakeSupplierConfirmService.getConfirmPicList(adMakeId, supplierIds);
                    if(CollectionUtils.isNotEmpty(supplierPicList)){
                        supplierPicMap = supplierPicList.stream().collect(Collectors.groupingBy(BillAdMakePicsForConfirmDTO::getSupplier_id,
                                Collectors.mapping(BillAdMakePicsForConfirmDTO::getPic_url, Collectors.toList())));

                    }
                    // 配送
                    Map<Long, List<BillAdMakeDeliverVO>> deliverSampleMap = new HashMap<>();
                    Map<Long, List<BillAdMakeDeliverVO>> deliverNormalMap = new HashMap<>();
                    List<BillAdMakeDeliverVO> delivers = billAdMakeDeliverService.deliverVOListByAdMakeIdAndSupplierIds(adMakeId, new ArrayList<>(supplierIds));
                    if(CollectionUtils.isNotEmpty(delivers)){
                        delivers.forEach(d -> {
                            if(d.getSample() == 1) {
                                List<BillAdMakeDeliverVO> list = deliverSampleMap.getOrDefault(d.getSupplier_id(), new ArrayList<>());
                                list.add(d);
                                deliverSampleMap.put(d.getSupplier_id(), list);
                            }
                            if(d.getSample() == 0) {
                                List<BillAdMakeDeliverVO> list = deliverNormalMap.getOrDefault(d.getSupplier_id(), new ArrayList<>());
                                list.add(d);
                                deliverNormalMap.put(d.getSupplier_id(), list);
                            }
                        });
                    }

                    Map<Long, List<String>> finalSupplierPicMap = supplierPicMap;
                    confirmVOs.forEach(vo -> {
                        vo.setPics(finalSupplierPicMap.getOrDefault(vo.getSupplier_id(), new ArrayList<>()));
                        vo.setDeliver_sample(deliverSampleMap.getOrDefault(vo.getSupplier_id(), new ArrayList<>()));
                        vo.setDeliver_normal(deliverNormalMap.getOrDefault(vo.getSupplier_id(), new ArrayList<>()));
                    });
                }
            }
            result.setConfirmVOList(confirmVOs);
        }

        return result;
    }

    @Override
    public List<BillAdMakeWebVO> selectDataList(BillAdMakeSearchParams params) {
        if(StringUtils.isNotBlank(params.getSupplier_ids_str())){
            String [] sIds = params.getSupplier_ids_str().split(",");
            params.setSupplier_ids(Arrays.stream(sIds).map(d -> Long.valueOf(d)).collect(Collectors.toList()));
        }
        List<BillAdMakeWebVO> vos = baseMapper.selectPageList(params);
        handleList(vos);
        return vos;
    }

    @Override
    public Page<BillAdMakeWebVO> selectPageList(BillAdMakeSearchParams params) {
        Page<BillAdMakeWebVO> page = params.createPage(BillAdMakeWebVO.class);
        if(StringUtils.isNotBlank(params.getSupplier_ids_str())){
            String [] sIds = params.getSupplier_ids_str().split(",");
            params.setSupplier_ids(Arrays.stream(sIds).map(d -> Long.valueOf(d)).collect(Collectors.toList()));
        }
        List<BillAdMakeWebVO> vos = baseMapper.selectPageList(page, params);
        handleList(vos);
        page.setRecords(vos);
        return page;
    }

    @Override
    public void exportSupplierDataExcel(HttpServletResponse response, BillAdMakeSearchParams params) {
        if(StringUtils.isNotBlank(params.getSupplier_ids_str())){
            String [] sIds = params.getSupplier_ids_str().split(",");
            params.setSupplier_ids(Arrays.stream(sIds).map(d -> Long.valueOf(d)).collect(Collectors.toList()));
        }
        List<BillAdMakeWebVO> vos = baseMapper.selectPageList(params);
        List<Long> ids = vos.stream().map(BillAdMakeWebVO::getId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(ids)) {
            List<BillAdMakePicCountVO> supplierPicCounts = baseMapper.getSupplierPicCount(ids);
            Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("供应商清单", "供应商清单"), BillAdMakePicCountVO.class, supplierPicCounts);
            try {
                response.setContentType("application/octet-stream");
                response.setHeader("Content-Disposition", "attachment; filename=" + "制作单导出-供应商清单" + ".xls");
                ServletOutputStream outputStream = response.getOutputStream();
                workbook.write(outputStream);
                outputStream.flush();
            } catch (Exception e) {
                throw new CommonException("导出失败");
            }
        }
    }

    private void handleList(List<BillAdMakeWebVO> vos){
        List<Long> ids = vos.stream().map(BillAdMakeWebVO::getId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(ids)) {

            List<BillAdMakePic> pics = billAdMakePicService.list(Wrappers.<BillAdMakePic>lambdaQuery().in(BillAdMakePic::getBill_ad_make_id, ids));
            Map<Long, List<String>> picMap = new HashMap<>();
            if(CollectionUtils.isNotEmpty(pics)) picMap = pics.stream().collect(Collectors.groupingBy(BillAdMakePic::getBill_ad_make_id, Collectors.mapping(BillAdMakePic::getPic_url, Collectors.toList())));

            List<BillAdMakeGenConfirmCountDTO> genConfirmCounts = baseMapper.getGenConfirmCount(ids);
            Map<Long, Integer> genMap = new HashMap<>();
            Map<Long, Integer> confirmMap = new HashMap<>();
            if(CollectionUtils.isNotEmpty(genConfirmCounts)){
                genConfirmCounts.stream().filter(d -> d.getAll_count() > 0).forEach(d -> {
                    int genStatus = AdMakeGenStatusEnum.NONE.getId();
                    if(d.getGen_count() > 0){
                        if(d.getGen_count() < d.getAll_count()) genStatus = AdMakeGenStatusEnum.PART.getId();
                        if(d.getGen_count().equals(d.getAll_count())) genStatus = AdMakeGenStatusEnum.ALL.getId();
                    }
                    int confirmStatus = AdMakeConfirmStatusEnum.NONE.getId();
                    if(d.getConfirm_count() > 0){
                        if(d.getConfirm_count() < d.getGen_count()) confirmStatus = AdMakeConfirmStatusEnum.PART.getId();
                        if(d.getConfirm_count().equals(d.getGen_count())) confirmStatus = AdMakeConfirmStatusEnum.ALL.getId();
                    }
                    genMap.put(d.getBill_ad_make_id(), genStatus);
                    confirmMap.put(d.getBill_ad_make_id(), confirmStatus);
                });
            }

            List<BillAdMakeMediaCountDTO> mediaCounts = baseMapper.getMediaTypeCount(ids);
            Map<Long, List<BillAdMakeMediaCountDTO>> mediaCountMap = new HashMap<>();
            if(CollectionUtils.isNotEmpty(mediaCounts)) mediaCountMap = mediaCounts.stream().collect(Collectors.groupingBy(BillAdMakeMediaCountDTO::getId));

            List<BillAdMakePicCountVO> supplierPicCounts = baseMapper.getSupplierPicCount(ids);
            Map<Long, List<BillAdMakePicCountVO>> supplierPicCountMap = new HashMap<>();
            if(CollectionUtils.isNotEmpty(supplierPicCounts)) supplierPicCountMap = supplierPicCounts.stream().collect(Collectors.groupingBy(BillAdMakePicCountVO::getId));

            for (BillAdMakeWebVO vo : vos) {
                vo.setPicList(picMap.getOrDefault(vo.getId(), new ArrayList<>()));
                vo.setGen_status(genMap.getOrDefault(vo.getId(), 1));
                vo.setConfirm_status(confirmMap.getOrDefault(vo.getId(), 1));
                if(vo.getDict_class_out_id() != null) vo.setDict_class_out_name(vo.getDict_class_out_id().getName());

                List<BillAdMakeMediaCountDTO> mcs = mediaCountMap.getOrDefault(vo.getId(), new ArrayList<>());
                vo.setMediaCountList(mcs);

                List<BillAdMakePicCountVO> spcs = supplierPicCountMap.getOrDefault(vo.getId(), new ArrayList<>());
                vo.setSupplierPicCountList(spcs);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String generateConfirmLink(BillAdMakeGenerateParams params) {
        BillAdMakeSupplierConfirm confirm = billAdMakeSupplierConfirmService.getConfirmByAdMakeIdAndSupplierId(params.getBill_ad_make_id(), params.getSupplier_id());
        if(confirm != null){
            String batchStr = IdUtil.fastSimpleUUID();
            billAdMakeSupplierConfirmService.update(Wrappers.<BillAdMakeSupplierConfirm>lambdaUpdate()
                    .set(BillAdMakeSupplierConfirm::getBatch_id, batchStr)
                    .eq(BillAdMakeSupplierConfirm::getId, confirm.getId()));
            return batchStr;
        }else{
            log.error("制作单，生成确认链接, 查询失败，adMakeId：{}，supplierId：{}",params.getBill_ad_make_id(), params.getSupplier_id());
            throw new CommonException("生成失败");
        }
    }

    @Override
    public String getConfirmLink(BillAdMakeGenerateParams params) {
        BillAdMakeSupplierConfirm confirm = billAdMakeSupplierConfirmService.getConfirmByAdMakeIdAndSupplierId(params.getBill_ad_make_id(), params.getSupplier_id());
        if(confirm != null){
            return confirm.getBatch_id();
        }else{
            log.error("制作单，获取确认链接, 查询失败，adMakeId：{}，supplierId：{}",params.getBill_ad_make_id(), params.getSupplier_id());
            throw new CommonException("获取失败");
        }
    }

    private void confirmSetPicList(BillAdMakeConfirmWebVO result, BillAdMakeSupplierConfirm confirm){
        boolean confirmed = StringUtils.isNotEmpty(confirm.getSign_img_url());
        BigDecimal total = new BigDecimal("0");
        List<BillAdMakeConfirmPicWebVO> discs = billAdMakeDisSupplierService.getDisConfirmVOList(confirm.getBill_ad_make_id(), confirm.getSupplier_id());
        if(CollectionUtils.isNotEmpty(discs)){
            for (BillAdMakeConfirmPicWebVO d : discs) {
                SupplierMaterialCalDTO calDTO = new SupplierMaterialCalDTO();
                calDTO.setConfirm_id(confirm.getId());
                calDTO.setSupplier_id(d.getSupplier_id());
                calDTO.setMaterial_texture_id(d.getPic_type_id());
                calDTO.setSize_width(d.getSize_width());
                calDTO.setSize_height(d.getSize_height());
                calDTO.setNum(d.getNum());
                if (confirmed) {
                    billAdMakeSupplierConfirmPriceService.calTotal(calDTO);
                } else {
                    supplierMaterialService.calTotal(calDTO);
                }
                d.setPrice(calDTO.getPrice());
                d.setSubtotal(calDTO.getTotal());
                total = total.add(calDTO.getTotal());
            }
            result.setPicList(discs);
            result.setTotal(total);
        }
    }

    @Override
    public BillAdMakeConfirmWebVO confirmBillDetail(String batchId) {
        BillAdMakeConfirmWebVO result = new BillAdMakeConfirmWebVO();
        BillAdMakeSupplierConfirm confirm = billAdMakeSupplierConfirmService.getConfirmVOById(batchId);
        if(confirm != null){
            BeanUtils.copyProperties(confirm, result);

            // 计算价格
            confirmSetPicList(result, confirm);

            // 配送
            List<Long> supplierIds = new ArrayList<>();
            supplierIds.add(confirm.getSupplier_id());
            List<BillAdMakeDeliverVO> deliverSample = new ArrayList<>();
            List<BillAdMakeDeliverVO> deliverNormal = new ArrayList<>();
            List<BillAdMakeDeliverVO> delivers = billAdMakeDeliverService.deliverVOListByAdMakeIdAndSupplierIds(confirm.getBill_ad_make_id(), supplierIds);
            if(CollectionUtils.isNotEmpty(delivers)){
                delivers.forEach(d -> {
                    if(d.getSample() == 1) {
                        deliverSample.add(d);
                    }
                    if(d.getSample() == 0) {
                        deliverNormal.add(d);
                    }
                });
            }
            result.setDeliver_sample(deliverSample);
            result.setDeliver_normal(deliverNormal);
        }
        return result;
    }

    @Override
    public BillAdMakeConfirmResult signConfirmBill(BillAdMakeSignParams params) {
        TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
        try {
            if(params.getTotal() == null || params.getTotal().compareTo(new BigDecimal("0")) == 0) throw new CommonException("确认单总价不得为空！");
            if(CollectionUtils.isEmpty(params.getPic_prices())) throw new CommonException("各材质单价不得为空！");

            Map<Long, BigDecimal> picPriceMap = params.getPic_prices().stream().collect(Collectors.toMap(BillAdMakePicTypePriceParams::getPic_type_id, BillAdMakePicTypePriceParams::getPrice));

            BillAdMakeSupplierConfirm confirm = billAdMakeSupplierConfirmService.getConfirmByBatchStr(params.getBatchStr());

            if(confirm != null){

                BillAdMakeConfirmWebVO detail = new BillAdMakeConfirmWebVO();
                confirmSetPicList(detail, confirm);
                if(detail.getTotal().compareTo(params.getTotal()) != 0) {
                    platformTransactionManager.rollback(transactionStatus);
                    return BillAdMakeConfirmResult.getResult(AdMakeConfirmResultEnum.TOTAL_WRONG);
                }

                billAdMakeSupplierConfirmService.update(Wrappers.<BillAdMakeSupplierConfirm>lambdaUpdate()
                        .set(BillAdMakeSupplierConfirm::getDeliver_time, params.getDeliver_time())
                        .set(BillAdMakeSupplierConfirm::getSign_img_url, params.getSignImgUrl())
                        .eq(BillAdMakeSupplierConfirm::getId, confirm.getId()));

                billAdMakeSupplierConfirmPriceService.remove(Wrappers.<BillAdMakeSupplierConfirmPrice>lambdaQuery()
                        .eq(BillAdMakeSupplierConfirmPrice::getConfirm_id, confirm.getId()));
                // 留存目前的单价
                List<BillAdMakeDisSupplier> diss = billAdMakeDisSupplierService.list(Wrappers.<BillAdMakeDisSupplier>lambdaQuery()
                        .eq(BillAdMakeDisSupplier::getBill_ad_make_id, confirm.getBill_ad_make_id())
                        .eq(BillAdMakeDisSupplier::getSupplier_id, confirm.getSupplier_id()));
                if(CollectionUtils.isNotEmpty(diss)){
                    Set<Long> picTypeIds = diss.stream().map(BillAdMakeDisSupplier::getPic_type_id).collect(Collectors.toSet());
                    if(CollectionUtils.isNotEmpty(picTypeIds)){
                        List<SupplierMaterial> ms = supplierMaterialService.list(Wrappers.<SupplierMaterial>lambdaQuery()
                                .eq(SupplierMaterial::getSupplier_id,confirm.getSupplier_id())
                                .in(SupplierMaterial::getMaterial_texture_id, picTypeIds)
                                .isNull(SupplierMaterial::getDeleted_at));
                        if(CollectionUtils.isNotEmpty(ms)){
                            List<BillAdMakeSupplierConfirmPrice> ps_temp = new ArrayList<>();
                            for (SupplierMaterial d : ms) {
                                if(picPriceMap.get(d.getMaterial_texture_id()) != null && picPriceMap.get(d.getMaterial_texture_id()).compareTo(d.getPrice()) == 0){
                                    BillAdMakeSupplierConfirmPrice temp = new BillAdMakeSupplierConfirmPrice();
                                    temp.setConfirm_id(confirm.getId());
                                    temp.setMaterial_texture_id(d.getMaterial_texture_id());
                                    temp.setPrice(d.getPrice());
                                    ps_temp.add(temp);
                                }else{
                                    platformTransactionManager.rollback(transactionStatus);
                                    return BillAdMakeConfirmResult.getResult(AdMakeConfirmResultEnum.PRICE_CHANGE);
                                }
                            }
                            List<BillAdMakeSupplierConfirmPrice> ps = ps_temp.stream()
                                    .distinct()
                                    .filter(d -> d.getConfirm_id()!=null && !d.getConfirm_id().equals(0L)).collect(Collectors.toList());
                            if(CollectionUtils.isNotEmpty(ps)) billAdMakeSupplierConfirmPriceService.saveBatch(ps);

                            // 设置确认总价
                            billAdMakeSupplierConfirmService.update(Wrappers.<BillAdMakeSupplierConfirm>lambdaUpdate()
                                    .set(BillAdMakeSupplierConfirm::getTotal, detail.getTotal())
                                    .set(BillAdMakeSupplierConfirm::getConfirm_time, LocalDateTime.now())
                                    .eq(BillAdMakeSupplierConfirm::getId, confirm.getId()));
                        } else {
                            throw new CommonException("材质数据异常，请联系管理员！");
                        }
                    } else {
                        throw new CommonException("分配数据异常，请联系管理员！");
                    }
                } else {
                    throw new CommonException("无分配数据，请联系管理员！");
                }
            } else {
                throw new CommonException("确认单不存在，请联系管理员！");
            }
            platformTransactionManager.commit(transactionStatus);
        } catch (Exception e) {
            platformTransactionManager.rollback(transactionStatus);
        }
        return BillAdMakeConfirmResult.getResult(AdMakeConfirmResultEnum.SUCCESS);
    }

    @Override
    public BillAdMakeWebVO getOneById(Long id) {
        BillAdMakeWebVO result = baseMapper.queryDetailById(id);
        if (result == null) throw new CommonException("数据不存在！");
        if (null != id) {
            Long userId = ThreadLocalUserUtil.get().getId();
            Boolean canCheck = WorkFlowUtil.canCheckData(userId, result);
            result.setCan_check(canCheck);
            result.setIs_applyer(userId.equals(result.getFlow_applyer_id()));
        } else {
            result.setIs_applyer(true);
        }

        fillDetail(result);

        return result;
    }


    private void fillDetail(BillAdMakeWebVO result) {
        if(result.getDict_class_out_id() != null) result.setDict_class_out_name(result.getDict_class_out_id().getName());

        List<BillAdMakePic> picVOs = billAdMakePicService.picVOListByAdMakeId(result.getId());
        if(CollectionUtils.isNotEmpty(picVOs)) result.setPicVOList(picVOs);

        List<BillAdMakeWebVO> markVOs = billAdMakeMarkService.markVOListByAdMakeId(result.getId());
        if(CollectionUtils.isNotEmpty(markVOs)) result.setMarkVOList(markVOs);

        List<BillAdMakeDisSupplierVO> disVOs = billAdMakeDisSupplierService.disVOListByAdMakeId(result.getId());
        if(CollectionUtils.isNotEmpty(disVOs)) result.setDisVOList(disVOs);

        List<BillAdMakeDeliverVO> deliverVOs = billAdMakeDeliverService.deliverVOListByAdMakeId(result.getId());
        if(CollectionUtils.isNotEmpty(deliverVOs)) result.setDeliverVOList(deliverVOs);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean save(BillAdMakeCreateParams params) {
        int flowResult = saveAndBegin(params, true);
        if (flowResult != 1) throw new CommonException("保存至草稿箱失败，请联系管理员！");
        else return true;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean begin(BillAdMakeCreateParams params) {
        // 提交
        int flowResult = saveAndBegin(params, false);
        if (flowResult == 1) {
            // 仍在流程中
            return true;
        } else if (flowResult == 2) {
            // 无审批节点，直接结束
            endProcess(params.getId());
            return true;
        } else {
            throw new CommonException("提交失败，请联系管理员！");
        }
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean pass(BillAdMakeCheckParams params) {
        // 通过
        int flowResult = passAndBack(params, true, false);
        if (flowResult == 1) {
            // 通过后仍然在流程中
            return true;
        } else if (flowResult == 2) {
            // 审核后流程结束
            endProcess(params.getId());
            return true;
        } else {
            throw new CommonException("通过失败，请联系管理员！");
        }
    }

    private void endProcess(Long id) {
        // 将标记的制作单，设置标记来源id
        List<BillAdMakeMark> marks = billAdMakeMarkService.list(Wrappers.<BillAdMakeMark>lambdaQuery().eq(BillAdMakeMark::getBill_ad_make_id, id));
        if(CollectionUtils.isNotEmpty(marks)){
            Set<Long> markIds = marks.stream().map(BillAdMakeMark::getMark_bill_ad_make_id).collect(Collectors.toSet());
            if(CollectionUtils.isNotEmpty(markIds)){
                update(Wrappers.<BillAdMake>lambdaUpdate().set(BillAdMake::getMark_from_bill_ad_make_id, id).in(BillAdMake::getId, markIds));
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean returnBack(BillAdMakeCheckParams params) {
        // 驳回
        int flowResult = passAndBack(params, false, false);
        if (flowResult != 1) throw new CommonException("驳回失败，请联系管理员！");
        return true;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean delete(Long id) {
        int flowResult = deleteAndActualDel(id, false);
        if (flowResult != 1) throw new CommonException("删除失败，请联系管理员！");
        return true;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean actualDelete(Long id) {
        int flowResult = deleteAndActualDel(id, true);
        if (flowResult != 1) throw new CommonException("彻底删除失败，请联系管理员！");
        return true;
    }

    /**
     * 处理子表数据
     * @param mainId 主表id
     * @param dto 入参结构体
     */
    private void handleSlaveData(Long mainId, BillAdMakeCreateParams dto){
        if(mainId == null) throw new CommonException("保存失败");
        if(CollectionUtils.isEmpty(dto.getPics())) throw new CommonException("无画面");
        if(CollectionUtils.isEmpty(dto.getDiss())) throw new CommonException("未分配供应商");
        if(CollectionUtils.isEmpty(dto.getDelivers())) throw new CommonException("未指定配送方式");

        // 画面
        billAdMakePicService.deleteByAdMakeId(mainId);
        List<BillAdMakePic> pics = dto.getPics().stream().map(d -> {
            BillAdMakePic temp = new BillAdMakePic();
            BeanUtils.copyProperties(d, temp);
            temp.setBill_ad_make_id(mainId);
            return temp;
        }).collect(Collectors.toList());
        billAdMakePicService.saveBatch(pics);
        Map<String, Long> picMap = pics.stream().collect(Collectors.toMap(BillAdMakePic::getUuid, BillAdMakePic::getId, (key1, key2) -> key2));

        // 标记
        billAdMakeMarkService.deleteByAdMakeId(mainId);
        if(CollectionUtils.isNotEmpty(dto.getMarks())){
            List<BillAdMakeMark> marks = dto.getMarks().stream().map(d -> {
                BillAdMakeMark temp = new BillAdMakeMark();
                BeanUtils.copyProperties(d, temp);
                temp.setBill_ad_make_id(mainId);
                return temp;
            }).collect(Collectors.toList());
            billAdMakeMarkService.saveBatch(marks);
        }

        // 分配供应商
        billAdMakeDisSupplierService.deleteByAdMakeId(mainId);
        List<BillAdMakeDisSupplier> diss = dto.getDiss().stream().map(d -> {
            BillAdMakeDisSupplier temp = new BillAdMakeDisSupplier();
            BeanUtils.copyProperties(d, temp);
            temp.setPic_id(picMap.getOrDefault(d.getPic_uuid(), -1L));
            temp.setBill_ad_make_id(mainId);
            return temp;
        }).collect(Collectors.toList());
        billAdMakeDisSupplierService.saveBatch(diss);

        // 配送
        billAdMakeDeliverService.deleteByAdMakeId(mainId);
        List<BillAdMakeDeliver> delivers = dto.getDelivers().stream().map(d -> {
            BillAdMakeDeliver temp = new BillAdMakeDeliver();
            BeanUtils.copyProperties(d, temp);
            temp.setBill_ad_make_id(mainId);
            return temp;
        }).collect(Collectors.toList());
        billAdMakeDeliverService.saveBatch(delivers);

        // 待生成链接数据对象
        billAdMakeSupplierConfirmService.deleteByAdMakeId(mainId);
        List<BillAdMakeSupplierConfirm> confirms = dto.getDiss().stream().map(d -> {
            BillAdMakeSupplierConfirm temp = new BillAdMakeSupplierConfirm();
            temp.setBill_ad_make_id(mainId);
            temp.setSupplier_id(d.getSupplier_id());
            return temp;
        }).distinct().collect(Collectors.toList());
        billAdMakeSupplierConfirmService.saveBatch(confirms);
    }

    private int saveAndBegin(BillAdMakeCreateParams dto, boolean isSave) {
        // 获取当前人的id和部门id
        UserForWFVO user = UserServiceImpl.getUserForWF(dto);
        BillAdMake temp = new BillAdMake();
        BeanUtils.copyProperties(dto, temp);

        CustomerInfo customerInfo = null;
        if(dto.getCustomer_id() != null) customerInfo = customerInfoService.getById(dto.getCustomer_id());

        // 设置流程字段，flow_type请自行对应“dict_flow_type”表中的id， 比如当前入职流程（考察登记流程）的id是5
        String flow_title = "制作单申请-" + (customerInfo != null ? customerInfo.getName() : "内单"); // 审批流程的名称，需要根据实际业务自行确定
        FlowBusinessDataSuperEntity fbdse = WorkFlowUtil.getStartSuperDataEntity(
                user.getUser_id(),  // 当前用户id
                user.getDep_id(), // 提交的部门id
                21, // 流程类型id，“dict_flow_type”表中的id
                flow_title // 自定义的流程标题
        );
        BeanUtils.copyProperties(fbdse, temp);

        // 是否为新数据
        // 新数据时，前端不传业务数据id
        // 非新数据时，即来源是“草稿箱”、“已删除”、“被退回”时，前端需要传入业务数据id
        boolean isFirst = (dto.getId() == null);

        // 由于流程字段含有id，会覆盖数据，此处需要手动setId
        if (!isFirst) temp.setId(dto.getId());

        // 新增或更新业务数据
        boolean flag = isFirst ? save(temp) : updateById(temp);
        if (!flag) throw new CommonException("保存失败");

        Long billAdMakeId = temp.getId();

        handleSlaveData(billAdMakeId, dto);

        // 构造流程工具类
        WorkFlowUtil wfu = new WorkFlowUtil<BillAdMake, BillAdMakeMapper>(billAdMakeId, user.getUser_id(), BillAdMake.class);

        // 审批流程id
        // 新数据,传0L
        // 非新数据,根据数据id,查找wfData_id
        Long wfData_id = isFirst ? 0L : wfu.getWfDataId(dto.getId());
        // 旧数据记录留存
        BillAdMake old_data = isFirst ? new BillAdMake() : temp;

        return isSave ? wfu.SaveDraft(wfData_id) : wfu.Begin(wfData_id, "", old_data);
    }

    // 通过 和 驳回 抽出相同代码
    private int passAndBack(BillAdMakeCheckParams dto, boolean isPass, boolean... updateData) {
        Long userId = ThreadLocalUserUtil.get().getId(); // 当前人id

        // 若业务数据有审批中可修改的内容，请自行更新
        if (updateData != null && updateData[0]) {
            BillAdMake updateTemp = new BillAdMake();
            BeanUtils.copyProperties(dto, updateTemp);
            updateById(updateTemp);
        }

        BillAdMake temp = getById(dto.getId()); // 业务数据
        WorkFlowUtil wfu = new WorkFlowUtil<BillAdMake, BillAdMakeMapper>(dto.getId(), userId, BillAdMake.class); // 构造流程工具类

        // 审批入参类
        WorkFlowCheckDTO checkDTO = WorkFlowCheckDTO.getWorkFlowCheckDTO(
                temp.getFlow_current_node_id(), // 当前节点id
                temp.getFlow_json(), // 流程json
                dto.getWf_check_opinion(), // 审批意见
                dto.getWf_check_sign_url(), // 审批签名链接
                JSONObject.toJSONString(temp) // 旧数据留存
        );

        // 审批
        return isPass ? wfu.ToNext(checkDTO) : wfu.ReturnBack(checkDTO);
    }

    // 删除 和 彻底删除 抽出相同代码
    private int deleteAndActualDel(Long id, boolean isActual) {
        Long userId = ThreadLocalUserUtil.get().getId(); // 当前人id
        WorkFlowUtil wfu = new WorkFlowUtil<BillAdMake, BillAdMakeMapper>(id, userId, BillAdMake.class); // 构造流程工具类
        Long wfData_id = wfu.getWfDataId(id); // 流程id
        return isActual ? wfu.ActualDelete(wfData_id) : wfu.Delete(wfData_id);
    }

}
